import { Graph, Addon, FunctionExt, Shape, View } from '@antv/x6'
import { message } from 'antd'
import './shape'
import axios from 'axios'

export default class FlowGraph {

  public static defaultEdgeColor = "#000000";  // 默认连线颜色
  public static inferenceEdgeColor = "#FF0000";  // 推理任务点击高亮线颜色

  public static graph: Graph
  private static stencil: Addon.Stencil
  private static flag: boolean

  public static pageType: string // 页面类型
  public static dataJson: any  // 总图数据
  public static removeCellsId: any[] // 移除的节点或连线的id
  public static nodes: any[] // 总图里面的节点
  // public static edges: any[] // 总图里的连线
  public static inferenceRecord: any
  public static inferenceDialogData: any // 单条推理任务数据
  public static ininferenceDialogDataResultChange: any // 单条推理任务数据推理变化
  public static inferenceId: any // 点击推理任务结果列表，记录当前推理任务结果id
  public static inferenceResultData: any // 推理结果列表数据
  public static msgList: any // 推理任务反馈信息
  public static resultMap: any // 订正用户反馈信息，记录节点是否正确
  public static feedbackData: any // 订正节点反馈信息

  public static reloadFeedback: any // 刷新订正页面反馈信息
  public static feedbackDialogData: any // 订正弹窗数据

  public static init() {
    let _this = this;
    this.removeCellsId = []
    this.nodes = []
    // this.edges = []
    this.dataJson = { cells: [] }
    this.inferenceRecord = undefined
    this.inferenceDialogData = undefined
    this.ininferenceDialogDataResultChange = false
    this.inferenceId = undefined
    this.inferenceResultData = []
    this.msgList = []
    this.resultMap = {}
    this.feedbackData = []
    this.reloadFeedback = undefined
    this.feedbackDialogData = undefined

    this.flag = true
    this.graph = new Graph({
      container: document.getElementById('container')!,
      resizing: {
        enabled: (node) => {
          if (node.data.type == '7') {
            return false;
          }
          return true;
        },
        orthogonal: false,
        preserveAspectRatio: true
      },
      panning: {
        enabled: true,
        eventTypes: ['leftMouseDown'],
      },
      mousewheel: {
        enabled: true,
        modifiers: [],
      },
      grid: {
        size: 10,
        visible: true,
        type: 'doubleMesh',
        args: [
          {
            color: '#cccccc',
            thickness: 1,
          },
          {
            color: '#5F95FF',
            thickness: 1,
            factor: 4,
          },
        ],
      },
      selecting: {
        enabled: true,
        multiple: true,
        rubberband: true,
        movable: true,
        showNodeSelectionBox: true,
        filter: ['groupNode'],
        modifiers: ['ctrl']
      },
      connecting: {
        anchor: 'center',
        connectionPoint: 'anchor',
        allowBlank: false,
        highlight: true,
        snap: true,
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: _this.defaultEdgeColor,
                strokeWidth: 1,
                targetMarker: {
                  name: 'classic',
                  size: 8,
                },
              },
            },
            router: {
              // name: 'manhattan',
            },
            zIndex: 0,
          })
        },
        validateConnection({
          sourceView,
          targetView,
          sourceMagnet,
          targetMagnet,
        }) {
          if (sourceView === targetView) {
            return false
          }
          if (!sourceMagnet) {
            return false
          }
          if (!targetMagnet) {
            return false
          }
          return true
        },
      },
      highlighting: {
        magnetAvailable: {
          name: 'stroke',
          args: {
            padding: 4,
            attrs: {
              strokeWidth: 4,
              stroke: 'rgba(223,234,255)',
            },
          },
        },
      },
      snapline: true,
      history: true,
      clipboard: {
        enabled: true,
      },
      keyboard: {
        enabled: true,
      },
      embedding: {
        enabled: true,
        findParent({ node }) {
          const bbox = node.getBBox()
          return this.getNodes().filter((node) => {
            // 只有 data.parent 为 true 的节点才是父节点
            const data = node.getData<any>()
            if (data && data.parent) {
              const targetBBox = node.getBBox()
              return bbox.isIntersectWithRect(targetBBox)
            }
            return false
          })
        },
      },
    })
    this.initStencil()
    this.initShape()
    this.initGraphShape(true)
    this.initEvent()
    return this.graph
  }

  private static initStencil() {
    let _this = this;
    this.stencil = new Addon.Stencil({
      title: "节点库",
      target: this.graph,
      stencilGraphWidth: 280,
      /*search: { rect: true },*/
      /*collapsable: true,*/
      groups: [
        {
          name: 'basic',
          title: '基础节点',
          graphHeight: 180,
        },
        {
          name: 'logic',
          title: '基础逻辑节点',
          graphHeight: 220,
          layoutOptions: {
            rowHeight: 90
          }
        },
        {
          name: 'logicGroup',
          title: '组合逻辑节点',
          graphHeight: 180,
          layoutOptions: {
            columns: 1,
            columnWidth: 260
          }
        },
      ],
      getDropNode(node, option) {  // 拖拽节点到画布放开鼠标后事件
        let data = node.data;
        if (data.type == "4" || data.type == "5" || data.type == "6" || data.type == "7") { // 去掉节点的标签
          node.setAttrs({ text: { style: { display: 'none' } } });
        }
        if (data.type == "7") {
          node.setAttrs({
            condition: {
              refX: '215%',
              refY: '45%'
            }
          });
          return node.clone().setSize(70, 70)
        }
        return node.clone();
      },
      validateNode(node) { // 验证节点是否可以拖拽到画布
        let data = node.data;
        if (data.type == "0") { // 描述节点添加判断，每个图只能存在一个描述节点
          let cells = _this.graph.getCells();
          if (cells && cells.length > 0) {
            for (let i = 0; i < cells.length; i++) {
              if (cells[i].data && cells[i].data.type == "0") {
                message.info("只能存在一个描述节点")
                return false;
              }
            }
          }
        }
        return true;
      }
    })
    const stencilContainer = document.querySelector('#stencil')
    stencilContainer?.appendChild(this.stencil.container)
  }

  private static initShape() {
    const { graph } = this
    const r1 = graph.createNode({
      shape: 'flow-chart-malfunction-rect',
      attrs: {
        text: {
          textWrap: {
            text: '故障描述',
          },
        },
      },
      data: {
        type: "0",
        text: '故障描述',
        score: "0"
      },
    })
    const r2 = graph.createNode({
      shape: 'flow-chart-rect',
      attrs: {
        text: {
          textWrap: {
            text: '处置节点',
          },
        },
      },
      data: {
        type: "1",
        text: '处置节点',
        score: '0'
      },
    })
    const r3 = graph.createNode({
      shape: 'flow-chart-phenomenon-rect',
      width: 80,
      height: 80,
      attrs: {
        'edit-text': {
        },
        text: {
          textWrap: {
            text: '现象节点',
          },
        },
      },
      ports: {
        groups: {
          top: {
            position: {
              name: 'top',
              args: {
                dx: 0,
                dy: 6,
              },
            },
          },
          right: {
            position: {
              name: 'right',
              args: {
                dx: -10,
                dy: 0,
              },
            },
          },
          bottom: {
            position: {
              name: 'bottom',
              args: {
                dx: 0,
                dy: -6,
              },
            },
          },
          left: {
            position: {
              name: 'left',
              args: {
                dx: 10,
                dy: 0,
              },
            },
          },
        },
      },
      data: {
        type: "2",
        text: '现象节点',
        score: '0'
      },
    })
    const r4 = graph.createNode({
      shape: 'flow-chart-custom-rect',
      width: 80,
      height: 60,
      attrs: {
        text: {
          textWrap: {
            text: '链接节点',
          },
        },
      },
      data: {
        type: "3",
        text: '链接节点',
        score: '0'
      },
    })

    /* const r5 = graph.createNode({
      shape: 'flow-chart-circle',
      width: 70,
      height: 70,
      attrs: {
        text: {
          textWrap: {
            text: '逻辑节点',
          },
        },
      },
      data: {
        type: "4",
        text: "逻辑节点"
      },
    }) */

    const orGate = graph.createNode({
      shape: 'flow-chart-orgate',
      width: 70,
      height: 70,
      attrs: {
        text: {
          textWrap: {
            text: '或门',
          }
        },
      },
      data: {
        type: "4",
        score: '0'
      },
    })

    const andGate = graph.createNode({
      shape: 'flow-chart-andgate',
      width: 70,
      height: 70,
      attrs: {
        text: {
          textWrap: {
            text: '与门',
          },
        },
      },
      data: {
        type: "5",
        text: "与门节点",
        score: '0'
      },
    })

    const notGate = graph.createNode({
      shape: 'flow-chart-notgate',
      width: 70,
      height: 70,
      attrs: {
        text: {
          textWrap: {
            text: '非门',
          },
        },
      },
      data: {
        type: "6",
        text: "非门节点",
        score: '0'
      },
    })

    const exclusiceOrGate = graph.createNode({
      shape: 'flow-chart-exclusiceorgate',
      width: 200,
      height: 70,
      attrs: {
        text: {
          textWrap: {
            text: '异或门',
          },
        },
        condition: {
          textWrap: {
            text: '',
          },
        },
      },
      data: {
        type: "7",
        text: "异或门节点",
        score: '0'
      },
    })

    const c1 = graph.createNode({
      shape: 'flow-chart-image-rect',
    })
    const c2 = graph.createNode({
      shape: 'flow-chart-title-rect',
    })
    const c3 = graph.createNode({
      shape: 'flow-chart-animate-text',
    })

    const g1 = graph.createNode({
      shape: 'groupNode',
      attrs: {
        text: {
          text: 'Group Name',
        },
      },
      data: {
        parent: true,
      },
    })
    this.stencil.load([r1, r2, r3, r4], 'basic')
    this.stencil.load([orGate, andGate, notGate], 'logic')
    this.stencil.load([exclusiceOrGate], 'logicGroup')
    this.stencil.load([c1, c2, c3], 'combination')
    this.stencil.load([g1], 'group')
  }

  public static initGraphShape(isLoadGraph: boolean) { // 加载总图数据 isLoadGraph 是否刷新画布
    let _this = this;
    let _graph = this.graph
    //this.graph.fromJSON(graphData as any)
    // @ts-ignore
    if (top.DIALOG) {
      // @ts-ignore
      let showId = top.DIALOG.showIds.top();
      if (showId) {
        // @ts-ignore
        let id = top.DIALOG.get(showId).state.data
        if (this.pageType == "2") {
          id = id.malId
        }
        let type = "0"
        if (this.pageType == "1") {
          type = "1"
          if (!id.malfunction_id) {
            return
          }
          id = id.malfunction_id
        }
        if (!this.pageType && typeof(id) != "string") {
          id = id.id;
        }
        axios.get("/OMDS/api/rest/malfunction/getContent/" + id + "/" + type)
          .then(function (res) {
            if (res.data.code == 200) {
              let resultMap = res.data.data
              if (resultMap.content != "" && resultMap.content != null) {
                let graphData = JSON.parse(resultMap.content)
                if (isLoadGraph) {
                  if (FlowGraph.inferenceDialogData) {
                    let feedBack = FlowGraph.inferenceDialogData.feedback;
                    if (typeof(feedBack) == "string") {
                      feedBack = JSON.parse(feedBack);
                      graphData.cells.map((cell: any) => {
                        let cellId = cell.id;
                        if (feedBack) {
                          if (feedBack[cellId]) {
                            cell.data.result = feedBack[cellId]
                          }
                        }
                      });
                    }
                  }
                  _graph.fromJSON(graphData as any)
                }

                _this.dataJson = graphData;
                if (_this.reloadFeedback) {
                  _this.reloadFeedback(_graph)
                }
                if (_this.pageType == "1") {
                  let cells = graphData.cells;
                  if (cells) {
                    // let edges: any[] = [];
                    let nodes: any[] = [];
                    cells.map((item: any, index: any) => {
                      // if (item.shape == "edge") {
                      //   edges.push(item)
                      //   return
                      // }
                      nodes.push(item)
                    })
                    // _this.edges = edges
                    _this.nodes = nodes
                  }
                }
              } else {
                let text = resultMap.text
                _graph.addNode({
                  shape: "flow-chart-malfunction-rect",
                  x: 330,
                  y: 30,
                  width: 80,
                  height: 42,
                  attrs: {
                    text: {
                      textWrap: {
                        text: text,
                      },
                    },
                  },
                  data: {
                    type: "0",
                    text: text
                  },
                })
              }
            } else {
              // @ts-ignore
              top.MSG.error("加载故障树失败!请稍后再试");
            }
          })
      }
    }
  }

  private static showPorts(ports: NodeListOf<SVGAElement>, show: boolean) {
    for (let i = 0, len = ports.length; i < len; i = i + 1) {
      ports[i].style.visibility = show ? 'visible' : 'hidden'
    }
  }

  private static initEvent() {
    const { graph } = this
    const container = document.getElementById('container')!

    graph.on('node:contextmenu', ({ cell, view }) => {
      let data = cell.data;
      let attrName = 'text';
      if (data.type == '7') {
        attrName = 'condition';
      }
      let oldText = cell.attr(attrName + '/textWrap/text') as string
      let fontSize = cell.attr(attrName + '/fontSize') as string
      let cellHeight = cell.size().height;
      const elem = view.container.querySelector('.x6-edit-text') as HTMLElement
      if (elem == null) { return }
      cell.attr(attrName + '/style/display', 'none')
      if (elem) {
        elem.style.display = ''
        elem.style.fontSize = fontSize + 'px'
        elem.contentEditable = 'true'
        elem.innerText = oldText
        elem.focus()

        // let selection = window.getSelection(); // 获取选中
        // let range = selection?.getRangeAt(0); // 获取光标
        // range?.setStart(range.startContainer, range.startContainer.length) // 设置光标位置
      }
      const onBlur = () => {
        const height = elem.scrollHeight;
        if (height >= cellHeight) {
          cell.setSize(cell.size().width, height + 10)
        }
        cell.attr(attrName + '/textWrap/text', elem.innerText)
        cell.attr(attrName + '/style/display', '')
        elem.style.display = 'none'
        elem.contentEditable = 'false'
      }
      elem.addEventListener('blur', () => {
        onBlur()
        elem.removeEventListener('blur', onBlur)
      })
    })

    graph.on('node:dblclick', ({ cell, view }) => {
      let data = cell.data;
      let attrName = 'text';
      if (data.type == '7') {
        attrName = 'condition';
      }
      const oldText = cell.attr(attrName + '/textWrap/text') as string
      const fontSize = cell.attr(attrName + '/fontSize') as string
      const elem = view.container.querySelector('.x6-edit-text') as HTMLElement
      if (elem == null) { return }
      cell.attr(attrName + '/style/display', 'none')
      if (elem) {
        elem.style.display = ''
        elem.style.fontSize = fontSize + 'px'
        elem.contentEditable = 'true'
        elem.innerText = oldText
        elem.focus()
      }
      const onBlur = () => {
        cell.attr(attrName + '/textWrap/text', elem.innerText)
        cell.attr(attrName + '/style/display', '')
        elem.style.display = 'none'
        elem.contentEditable = 'false'
      }
      elem.addEventListener('blur', () => {
        onBlur()
        elem.removeEventListener('blur', onBlur)
      })
    })

    /* graph.on('edge:dblclick', ({ edge, view }) => {
       const flag = this.flag;
       let value = "否"
       if(flag){
         value="是"
       }
       edge.appendLabel({
         attrs: {
           text: {
             text: value,
           },
         },
       })
       this.flag = !flag;
     })

     graph.on('edge:contextmenu', ({e,x,y, edge, view }) => {
       edge.removeLabelAt(0);
     })
 */
    graph.on(
      'node:mouseenter',
      FunctionExt.debounce(() => {
        const ports = container.querySelectorAll(
          '.x6-port-body',
        ) as NodeListOf<SVGAElement>
        this.showPorts(ports, true)
      }),
      500,
    )
    graph.on('node:mouseleave', () => {
      const ports = container.querySelectorAll(
        '.x6-port-body',
      ) as NodeListOf<SVGAElement>
      this.showPorts(ports, false)
    })

    // @ts-ignore
    graph.on('node:collapse', ({ node, e }) => {
      e.stopPropagation()
      node.toggleCollapse()
      const collapsed = node.isCollapsed()
      const cells = node.getDescendants()
      // @ts-ignore
      cells.forEach((n) => {
        if (collapsed) {
          n.hide()
        } else {
          n.show()
        }
      })
    })

    graph.on('node:embedded', ({ cell }) => {
      if (cell.shape !== 'groupNode') {
        cell.toFront()
      }
    })

    graph.bindKey('delete', () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        cells.forEach((cell) => {
          if (cell.data && cell.data.type == "0") { // 描述节点不给删除
            message.info("不可删除描述节点")
            return
          }
          this.removeCellsId.push(cell.id)
          graph.removeCell(cell)
        })
      }
    })
  }

  public static getContentCells = (ids: any) => { // 根据推理结果列表保存的节点id高亮总图中的节点信息

    this.graph.startBatch('changeEdgeColor')
    let edges = this.graph.getEdges();

    // 高亮连线前先重置连线颜色
    edges.map((edge) => {
      edge.attr('line/stroke', this.defaultEdgeColor)
    });

    ids.map((id: any, idIndex: any) => {
      for (let nodeIndex = 0; nodeIndex < this.nodes.length; nodeIndex++) {
        let node = this.nodes[nodeIndex];
        if (node.id == id) {
          for (let edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
            let edge = edges[edgeIndex];
            let source: any = edge.source;
            let target: any = edge.target;
            if (source.cell == id && ids.indexOf(target.cell) != -1) {
              edge.attr('line/stroke', this.inferenceEdgeColor)
            }
          }
          break;
        }
      }
    })

    this.graph.stopBatch('changeEdgeColor')
  }

  public static updateInferenceResultData = (val: any, cell: any) => { // 更新推理结果分数
    let cellId = cell.id;
    this.inferenceResultData.map((resultData: any) => {
      let node_id = resultData.node_id;

      if (typeof (node_id) == "string") {
        node_id = JSON.parse(node_id);
      }
      if (node_id.indexOf(cellId) != -1) {
        if (val == "1") {
          resultData.confidence++;
        }
        if (val == "0") {
          if (resultData.confidence > resultData.defaultConfidence) {
            resultData.confidence--;
          }
        }
      }
    })
  }
}
